﻿using System;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using PicHunter.Logging;
using PicHunter.Task;
using PicHunter.Task.Impl;

namespace PicHunter
{
    public partial class MainForm : Form, ILogListener
    {
        Log LOG = Log.Instance;

        public String RootDir { get; private set; }

        public MainForm()
        {
            InitializeComponent();
            LOG.AddListener(this);
            LOG.Info("Application start");

            // CheckCreateRoot
            CheckCreateRoot();

            // Init tree
            InitFileTree(null, RootDir);
        }

        #region Init UI
        private void CheckCreateRoot()
        {
            string rootDir = AppDomain.CurrentDomain.BaseDirectory;
            if (!rootDir.EndsWith(@"\"))
            {
                rootDir += @"\root";
            }
            else
            {
                rootDir += @"root";
            }
            RootDir = rootDir;

            if (!Directory.Exists(rootDir))
            {
                Directory.CreateDirectory(rootDir);
            }
        }

        private void InitFileTree(TreeNode startNode, String startDir)
        {
            if (startNode == null)
            {
                startNode = treeView.Nodes.Add("/");
                DirNodeTag tag = new DirNodeTag();
                tag.Path = RootDir;
                startNode.Tag = tag;
            }
            try
            {
                foreach (var v in Directory.GetDirectories(startDir))
                {
                    TreeNode node = startNode.Nodes.Add(v.Substring(v.LastIndexOf(@"\") + 1));
                    DirNodeTag tag = new DirNodeTag();
                    tag.Path = v;
                    node.Tag = tag;
                    InitFileTree(node, v);
                }
            }
            catch (Exception ex)
            {
                LOG.Error(ex);
            }
        }

        #endregion

        #region ILogListener Members

        public void OnLogEvent(LogMessage lm)
        {
            if (lm == null) return;
          
            ListViewItem item = new ListViewItem();
            item.Text = lm.ThreadId.ToString();
            item.SubItems.Add(lm.Date.ToString());
            item.SubItems.Add(lm.Message.ToString());
            // color
            switch (lm.Level)
            {
                case LogMessageLevel.INFO:
                    //item.BackColor = Color.Cyan;
                    break;
                default:
                    break;
            }
            if (listViewLog.InvokeRequired)
            {
                listViewLog.Invoke((Action)delegate { listViewLog.Items.Add(item); });
            }
            else
            {
                listViewLog.Items.Add(item);
            }
        }

        #endregion

        #region Click Events
        private void menuClearAllLog_Click(object sender, System.EventArgs e)
        {
            listViewLog.Clear();
        }

        private void btnNewUrl_Click(object sender, System.EventArgs e)
        {
            NewForm form = new NewForm();
            DialogResult result = form.ShowDialog();
            if (result != DialogResult.OK) return;

            // check
            if (form.NAME == null || form.NAME.Trim().Equals("")) return;
            if (form.URL == null || form.URL.Trim().Equals("")) return;

            // crete node
            if (form.NAME == null || form.NAME.Trim().Equals("")) return;
            TreeNode node = treeView.Nodes[0].Nodes.Add(form.NAME);
            node.Tag = form.URL;

            // create dir 
            String TARGET = form.URL.ToString();
            int startPos = TARGET.LastIndexOf("/") + 1;
            int endPos = TARGET.LastIndexOf(".");
            String dir = @"root\" + TARGET.Substring(startPos, endPos - startPos);
            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);

            // get pages
            StringCollection stringCollection = new StringCollection();
            try
            {
                Match m = Regex.Match(TARGET, @"\[(\d*)-(\d*)\]");
                if (m.Success)
                {
                    Int32 iStart = Int32.Parse(m.Groups[1].Value);
                    Int32 iEnd = Int32.Parse(m.Groups[2].Value);
                    for (; iStart <= iEnd; ++iStart)
                        stringCollection.Add(TARGET.Replace(m.Groups[0].Value, iStart.ToString()));
                }
                else
                {
                    stringCollection.Add(TARGET);
                }
            }
            catch (ArgumentException ex)
            {
                LOG.Warn(ex.Message);
            }

            // get pic urls
            foreach (var v in stringCollection)
            {
                ReadPicUrlsTask t = new ReadPicUrlsTask();
                t.PageUri = v;
                t.Completed += new TaskCompleted(delegate() 
                    {
                        foreach (var i in t.Result)
                        {
                            DownloadPicTask dpt = new DownloadPicTask();
                            dpt.URL = i;
                            dpt.DIR = dir;
                            ThreadPool.QueueUserWorkItem(new WaitCallback((arg) =>
                            {
                                PicHunter.Task.Task task = arg as PicHunter.Task.Task;
                                if (task != null)
                                {
                                    task.DoWork();
                                }
                            }), dpt);
                        }
                    });
                ThreadPool.QueueUserWorkItem(new WaitCallback((arg) =>
                    {
                        PicHunter.Task.Task task = arg as PicHunter.Task.Task;
                        if (task != null)
                        {
                            task.DoWork();
                        }
                    }), t);
            }
        }

        private void btnNewDir_Click(object sender, EventArgs e)
        {

        }

        private void menuItemNewFile_Click(object sender, EventArgs e)
        {

        }

        private void menuItemNewDir_Click(object sender, EventArgs e)
        {
            TreeNode node = treeView.SelectedNode;
            if (node == null)
            {
                LOG.Warn("No selected node");
                return;
            }
            string newName = @"新しいフォルダ";
            string newPath = ((DirNodeTag)node.Tag).Path + @"\" + newName;
            Directory.CreateDirectory(newPath);
            TreeNode newNode = node.Nodes.Add(newName);
            DirNodeTag tag = new DirNodeTag();
            tag.Path = newPath;
            newNode.Tag = tag;
        }

        private void menuItemDelete_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Delete Selected Node?",
                "", MessageBoxButtons.YesNo, MessageBoxIcon.Question,
                MessageBoxDefaultButton.Button2) != DialogResult.Yes)
                return;

            TreeNode node = treeView.SelectedNode;
            if (node == null)
            {
                LOG.Warn("No selected node");
                return;
            }
            String path = ((DirNodeTag)node.Tag).Path;
            try
            {
                Directory.Delete(path, true);
                node.Remove();
            }
            catch (Exception ex)
            {
                LOG.Error(ex);
            }
        }
        #endregion

        void ReadPageTaskProc(ReadPageTask task)
        {
            String dir = task.DIR;
            String TARGET = task.URL;

            String page = "";
            try
            {
                WebClient client = new WebClient();
                LOG.Info("Downloading ... " + TARGET);
                page = client.DownloadString(TARGET);
            }
            catch (Exception ex)
            {
                LOG.Error(String.Format("ERROR: {0}", ex.Message));
            }

            // get match
            StringCollection resultList = new StringCollection();
            try
            {
                Regex regexObj = new Regex(@"http://[.\w.-_]*?\.jpg");
                Match matchResult = regexObj.Match(page);
                while (matchResult.Success)
                {
                    resultList.Add(matchResult.Value);
                    matchResult = matchResult.NextMatch();
                }
            }
            catch (ArgumentException ex)
            {
                LOG.Error(String.Format("ERROR: {0}", ex.Message));
            }

            LOG.Info(String.Format("Get {0} pictures", resultList.Count));
            
            for (int i = 0; i < resultList.Count; ++i)
            {
                String item = resultList[i];

                DownloadPictureTask downloadPicTask = new DownloadPictureTask();
                downloadPicTask.DIR = dir;
                downloadPicTask.URL = item;
                ThreadPool.QueueUserWorkItem(new WaitCallback((t)=>
                    {
                        DownloadPictureTaskProc(t as DownloadPictureTask);
                    }), downloadPicTask);
            }
        }

        void DownloadPictureTaskProc(DownloadPictureTask task)
        {
            String item = task.URL;
            String dir = task.DIR;
            // filename
            int pos = item.LastIndexOf("/") + 1;
            string filename = item.Substring(pos);
            string filepath = String.Format(@"{0}\{1}", dir, filename);

            if (File.Exists(filepath))
            {
                LOG.Debug(String.Format("{0} aready exits, skip", filename));
                return;
            }

            LOG.Info(String.Format("Downloading... {0})", item));

            try
            {
                WebClient client = new WebClient();
                client.DownloadFile(item, filepath);
            }
            catch (Exception ex)
            {
                LOG.Error(String.Format("ERROR: {0}", ex.Message));
            }
        }

    }
}
